import { CommonFunction } from "./CommonFunction";
import { GlobalDefinition } from "./GlobalDefinition";
import { DrawClass } from "./DrawClass"
import { OG } from "./CommonClass";
import { GlobalClass } from "./GlobalClass";
import { EventDefinition } from "./EventDefinition";
import { DataRecordClass } from "./DataRecordClass";

/**mainCanvas控制类*/
export class MainCanvasClass {
    private static self: MainCanvasClass;
    private mainCanvas: HTMLCanvasElement;  //主绘制Canvas
    private bgCanvas: HTMLCanvasElement;  //背景canvas
    private fgCanvas: HTMLCanvasElement;  //前景Canvas
    private comm: CommonFunction;
    private drcs: DataRecordClass;
    private mainCanvasSize:OG.Size;
    private imgSource:any;   //图片资源
    private drawPos:OG.Positon;  //图块绘制坐标
    private blockSize:OG.Size;
    private optionState: StateOption;  //操作状态
    private clickRW: {row:number,line:number} = {row:-1,line:-1};  //点击绘制的行列信息
    private MapInfo: HTMLDivElement;
    private PosInfo: HTMLDivElement;
    private leftFunc: HTMLDivElement;
    private rightFunc: HTMLDivElement;
    private containerDiv: HTMLDivElement;
    private setBlockAngle: HTMLDivElement;
    private rotateInterval:number = 90;  //旋转角度间隔
    private rotateCurrent:number = 0;  //当前设置的旋转角度

    public static ins() {
        if (this.self != null) {
            return MainCanvasClass.self;
        } else {
            return new MainCanvasClass();
        }
    }

    public constructor() {
        this.clickRW.row = -1;
        this.clickRW.line = -1;
        this.mainCanvasSize = new OG.Size();
        this.drawPos = new OG.Positon();
        this.blockSize = new OG.Size();
        this.optionState = new StateOption();
        this.comm = CommonFunction.ins();
        this.drcs = DataRecordClass.ins();
        MainCanvasClass.self = this;
        this.mainCanvasSize.width = GlobalDefinition.MainCanvasWidth;
        this.mainCanvasSize.height = GlobalDefinition.MainCanvasHeight;
        this.InitClass();
        this.InitListener();
        this.SetForgroundPaint();
    }

    /**初始化 */
    private InitClass() {
        this.mainCanvas = this.comm.IdToElement("mainCanvas") as HTMLCanvasElement;
        this.bgCanvas = this.comm.IdToElement("bgCanvas") as HTMLCanvasElement;
        this.fgCanvas = this.comm.IdToElement("fgCanvas") as HTMLCanvasElement;
        this.MapInfo = this.comm.IdToElement("mapInfo") as HTMLDivElement;
        this.PosInfo = this.comm.IdToElement("posInfo") as HTMLDivElement;
        this.leftFunc = this.comm.IdToElement("leftFunc") as HTMLDivElement;
        this.rightFunc = this.comm.IdToElement("rightFunc") as HTMLDivElement;
        this.containerDiv = this.comm.IdToElement("container") as HTMLDivElement;
        this.setBlockAngle = this.comm.IdToElement("setBlockAngle") as HTMLDivElement;
        this.SetWidth(GlobalDefinition.MainCanvasWidth);
        this.SetHeight(GlobalDefinition.MainCanvasHeight);
        this.SetCanvasBg(screen);
        this.CenterMainCanvas();  //居中是以bgCanvas宽高为基准,因此要在设置完bgCanvas宽高之后
        this.UpdateDrawGrid();
    }

    /**初始化监听*/
    public InitListener() {
        GlobalClass.ListenerCenter.addEvent(EventDefinition.MOVE, this.mainCanvas, this.listenerCall.bind(this));
        GlobalClass.ListenerCenter.addEvent(EventDefinition.CLICK,this.mainCanvas,this.LeftClickCall.bind(this));
        GlobalClass.ListenerCenter.addEvent(EventDefinition.MOUSEDOWN,this.mainCanvas,this.DownCall.bind(this));
        GlobalClass.ListenerCenter.addEvent(EventDefinition.MOUSEUP,this.mainCanvas,this.UpCall.bind(this));
        GlobalClass.ListenerCenter.addEvent(EventDefinition.KEYDOWN,document.body,this.BlockDirection.bind(this));
        this.mainCanvas.oncontextmenu = this.RightClick.bind(this);  //禁止鼠标右键原生操作
        this.leftFunc.oncontextmenu = this.RightMenu.bind(this);
        this.rightFunc.oncontextmenu = this.RightMenu.bind(this);
        this.containerDiv.oncontextmenu = this.RightMenu.bind(this);
    }

    /**设置fgCanvas的画笔*/
    public SetForgroundPaint () {
        DrawClass.ins().BindCanvas(this.fgCanvas);
        let paint_brush: OG.PaintBrush = new OG.PaintBrush(this.fgCanvas.getContext("2d"));  //设置画笔
        paint_brush.fillStyle = "rgba(100,150,185,0.4)";
        DrawClass.ins().BindContext(paint_brush.UpdateBrush());
    }

    /**设置mainCanvas宽度 */
    public SetWidth(w: number) {
        this.mainCanvas.width = w;
        this.mainCanvas.style.width = w + "px";
        GlobalDefinition.MainCanvasWidth = w;
    }

    /**设置mainCanvas高度 */
    public SetHeight(h: number) {
        this.mainCanvas.height = h;
        this.mainCanvas.style.height = h + "px";
        GlobalDefinition.MainCanvasHeight = h;
    }

    /**居中mainCanvas与fgCanvas
     * 
     * Canvas标签在重新设置宽高后,会将自身的绘图属性重置为默认值(如fillStyle等)
    */
    public CenterMainCanvas() {
        let refc:OG.Size = new OG.Size();
        let mainSize:OG.Size = new OG.Size();
        mainSize.width = GlobalDefinition.MainCanvasWidth;
        mainSize.height = GlobalDefinition.MainCanvasHeight;
        refc.width = GlobalDefinition.BgCanvasWidth;
        refc.height = GlobalDefinition.BgCanvasHeight;
        //若maincanvas宽度超过mainFunc功能区最大宽度则此时不做居中,
        //以mainCanvas的宽度做参照 使得mainCanvas可以全览
        if(this.mainCanvas.width > (screen.width - 600)) {
            refc.width = this.mainCanvas.width;
        }
        if(this.mainCanvas.height > screen.height) {
            refc.height = this.mainCanvas.height;
        }
        this.mainCanvas.width = GlobalDefinition.MainCanvasWidth
        this.mainCanvas.height = GlobalDefinition.MainCanvasHeight
        this.fgCanvas.width = GlobalDefinition.MainCanvasWidth;
        this.fgCanvas.height = GlobalDefinition.MainCanvasHeight;
        this.mainCanvas.style.width = GlobalDefinition.MainCanvasWidth + "px";
        this.mainCanvas.style.height = GlobalDefinition.MainCanvasHeight + "px";
        this.fgCanvas.style.width = GlobalDefinition.MainCanvasWidth + "px";
        this.fgCanvas.style.height = GlobalDefinition.MainCanvasHeight + "px";
        MainCanvasClass.ins().FixCanvasBg(mainSize);
        this.comm.CenterElement(this.mainCanvas, refc, "HV");
        this.comm.CenterElement(this.fgCanvas,refc,"HV");
        this.SetForgroundPaint();
    }

    /**返回mainCanvas宽高*/
    public ReturnCanvasHV(): OG.Size {
        let HV: OG.Size = new OG.Size(this.mainCanvas.width, this.mainCanvas.height);
        return HV;
    }

    /**返回以B元荤相对于元素A的距离 */
    public RelativeSize(A: OG.Positon, B: OG.Positon) {
        let r_size: OG.Size = new OG.Size();
        let h_ins: number = Math.abs(B.x - A.x);
        let v_ins: number = Math.abs(B.y - A.y);
        r_size.width = h_ins;
        r_size.height = v_ins;
        return r_size;
    }

    /**绘制背景网格 
     * @param int_h 网格横向间隔
     * @param int_v 网格纵向间隔
     * @param grid_sumH 网格横向数量
     * @param grid_sumV 网格纵向数量
    */
    public DrawGridBg(int_h: number, int_v: number, grid_sumH: number, grid_sumV: number) {
        //背景Canvas位置
        let bgc_pos: OG.Positon = new OG.Positon();
        let error: number = 2 / grid_sumH;  //误差补正
        let main_size: OG.Size = this.ReturnCanvasHV();
        let left: number = parseInt(this.mainCanvas.style.marginLeft.replace(" px", ""));  //以[mainCanva]的marginLeft值为X
        let top: number = parseInt(this.mainCanvas.style.marginTop.replace(" px", ""));  //以[mainCanva]的marginTop值为Y
        let main_pos: OG.Positon = new OG.Positon(left, top);  //mainCanvas位置
        let rel_size: OG.Size = this.RelativeSize(bgc_pos, main_pos);
        let temp_start: OG.Positon = new OG.Positon();  //临时起点
        let temp_end: OG.Positon = new OG.Positon();  //临时终点
        //网格起始位置
        let grid_start: OG.Positon = new OG.Positon(rel_size.width, 0);
        //网格结束位置
        let grid_end: OG.Positon = new OG.Positon();
        let paint_brush: OG.PaintBrush = new OG.PaintBrush(this.bgCanvas.getContext("2d"));  //设置画笔
        paint_brush.strokeStyle = "pink";
        grid_end.x = grid_start.x + main_size.width;
        grid_end.y = grid_start.x + main_size.height + top;

        //开始绘制
        DrawClass.ins().BindCanvas(this.bgCanvas);
        DrawClass.ins().BindContext(paint_brush.UpdateBrush());
        temp_start.x = grid_start.x;
        temp_start.y = grid_start.y;
        temp_end.x = grid_start.x;
        temp_end.y = grid_end.y;

        //绘制横向线条
        for (let inx = 0; inx <= grid_sumH; inx++) {
            DrawClass.ins().DottedLine(2, 4, temp_start, temp_end);
            temp_start.x += int_h + error;
            temp_end.x += int_h + error;
        }
        temp_start.x = 0;
        temp_start.y = rel_size.height;
        temp_end.x = grid_end.x + rel_size.width;
        temp_end.y = rel_size.height;
        error = 2 / grid_sumV;
        //绘制纵向线条
        for (let inx = 0; inx <= grid_sumV; inx++) {
            DrawClass.ins().DottedLine(2, 4, temp_start, temp_end);
            temp_start.y += int_v + error;
            temp_end.y += int_v + error;
        }
    }

    /**根据屏幕设置背景Canvas的大小 */
    public SetCanvasBg(Scr: Screen) {
        let bg_width: number = Scr.width - 600;
        let bg_height: number = GlobalDefinition.BgCanvasHeight;
        this.bgCanvas.width = bg_width;
        this.bgCanvas.height = bg_height;
        this.bgCanvas.style.width = bg_width + "px";
        this.bgCanvas.style.height = bg_height + "px";
        GlobalDefinition.BgCanvasWidth = bg_width;
        GlobalDefinition.BgCanvasHeight = bg_height;
    }

    /**根据mainCanvas宽高修正背景Canvas的大小*/
    public FixCanvasBg (main_size:OG.Size) {
        let currSize:OG.Size = new OG.Size();  //当前宽高
        currSize.width = GlobalDefinition.BgCanvasWidth;
        currSize.height = GlobalDefinition.BgCanvasHeight;
        if(main_size.width >= GlobalDefinition.BgCanvasWidth) {
            this.bgCanvas.width = main_size.width;
            this.bgCanvas.style.width = main_size.width  + "px";
        }
        if(main_size.height >= GlobalDefinition.BgCanvasHeight) {
            this.bgCanvas.height = main_size.height ;
            this.bgCanvas.style.height = main_size.height  + "px";
        }
        GlobalDefinition.BgCanvasWidth = currSize.width;
        GlobalDefinition.BgCanvasHeight = currSize.height;
    }

    /**更新网格绘制*/
    public UpdateDrawGrid() {
        let c_size: OG.Size = new OG.Size();
        c_size.width = this.bgCanvas.width;
        c_size.height = this.bgCanvas.height;
        this.blockSize.width = GlobalDefinition.BlockWidth;
        this.blockSize.height = GlobalDefinition.BlockHeight;
        DrawClass.ins().ClearAllCanvas(c_size, this.bgCanvas.getContext("2d"));
        this.DrawGridBg(GlobalDefinition.BlockWidth, GlobalDefinition.BlockHeight,
            GlobalDefinition.BlockWidthSum, GlobalDefinition.BlockHeightSum);
    }

    /**查找并返回要绘制的正确位置 
     * @param mouse_pos 鼠标位置
    */
    public CheckMoveBlock(mouse_pos: OG.Positon) {
        let block_pos:OG.Positon = new OG.Positon();
        let block_sum_h: number = 0;  //到达的横向第X个图块
        let block_sum_v: number = 0;  //到达的纵向第Y个图块
        let sum_h: number = GlobalDefinition.BlockWidthSum;  //横向图块总数
        let sum_v: number = GlobalDefinition.BlockHeightSum;  //纵向图块总数
        let block_w: number = GlobalDefinition.BlockWidth;  //图块宽度
        let block_h: number = GlobalDefinition.BlockHeight;  //图块高度
        //判断横向[等于sum_h是为了计算最后一个]
        for (let x = 0; x <= sum_h; x++) {
            //若横向小于当前某个图块，则点击位置表示位于(X-2)与X之间
            if (mouse_pos.x < (block_w * x) == true) {
                if (x - 1 == -1) {
                    block_sum_h = 0;
                    break;
                } else {
                    block_sum_h = x - 1;
                    break;
                }
            }
        }

        //判断横向[等于sum_h是为了计算最后一个]
        for (let y = 0; y <= sum_v; y++) {
            //若横向小于当前某个图块，则点击位置表示位于(y-2)与y之间
            if (mouse_pos.y < (block_h * y) == true) {
                if (y - 1 == -1) {
                    block_sum_v = 0;
                    break;
                } else {
                    block_sum_v = y - 1;
                    break;
                }
            }
        }
        block_pos.x = block_w * block_sum_h;
        block_pos.y = block_h * block_sum_v;
        this.clickRW.row = block_sum_h;
        this.clickRW.line = block_sum_v;
        //显示行列信息
        this.MapInfo.textContent = "[ " + block_sum_h + " , " + block_sum_v + " ]";
        return block_pos;
    }

    /**绘制并显示鼠标移动到的图块
     * @param mo_pos 移动到的图块位置
    */
    public ShowMoveBlock (mo_pos:OG.Positon) {
        let temp:OG.Size = new OG.Size(GlobalDefinition.BlockWidth,GlobalDefinition.BlockHeight);
        DrawClass.ins().ClearAllCanvas(this.fgCanvas,this.fgCanvas.getContext("2d"));
        DrawClass.ins().BindCanvas(this.fgCanvas);
        DrawClass.ins().DrawRect(mo_pos,temp,true);
    }

    /**设置图片
     * @param imgs 图片资源
    */
    public SettingImage (imgs:any) {
        this.imgSource = imgs;
    }

    /**左键点击绘制图块
     * @param block_size 图块大小
     * @param block_pos 图块位置
     * @param imgs 绘制资源
    */
    public ClickDrawBlock (block_size:OG.Size,block_pos:OG.Positon,imgs:any) {
        let start_pos:OG.Positon = new OG.Positon();
        if(imgs == null) {
            return;
        }       
        DrawClass.ins().BindCanvas(this.mainCanvas);
        DrawClass.ins().PaintImage(imgs,start_pos,block_size,block_pos);
    }

    /**右键点击清除图块
     * @param block_pos 图块位置
     * @param block_size 图块大小
    */
    public ClickDeleBlock(block_pos: OG.Positon,block_size: OG.Size) {
        DrawClass.ins().BindCanvas(this.mainCanvas);
        DrawClass.ins().DeleteImage(block_pos,block_size);
    }

    /**鼠标移动监听回调 */
    private listenerCall(e, event) {
        let x: number = event.offsetX;
        let y: number = event.offsetY;
        this.optionState.MouseMove_Block = true;
        let mp: OG.Positon = new OG.Positon(x, y);
        this.drawPos = this.CheckMoveBlock(mp);
        this.PosInfo.textContent = "[ X " + x + " , " + y + " ]";
        if(this.optionState.LeftMouse_Down == true) {
            if(this.imgSource != null) {
                let tag:number = this.GetImageIndex(this.imgSource.title);
                this.drcs.AddArrTag(this.clickRW.line,this.clickRW.row,tag);
            }
            this.ClickDrawBlock(this.blockSize,this.drawPos,this.imgSource);
        }else if(this.optionState.RightMouse_Down == true)
        {
            this.drcs.AddArrTag(this.clickRW.line,this.clickRW.row,0);  //相应的地图数组下标置为0
            this.ClickDeleBlock(this.drawPos,this.blockSize);
        }
        else
        {
            this.ShowMoveBlock(this.drawPos);
        }
    }

    /**鼠标左键点击监听回调*/
    private LeftClickCall(e,event) {
        this.optionState.LeftMouse_Click = true;
        switch(event.button) {
            case 0:
                if(this.imgSource != null) {
                    let tag:number = this.GetImageIndex(this.imgSource.title);
                    this.drcs.AddArrTag(this.clickRW.line,this.clickRW.row,tag);
                }
                this.ClickDrawBlock(this.blockSize,this.drawPos,this.imgSource);
            break;
        }
    }

    /**鼠标按下不松开回调 */
    private DownCall (e,event) { 
        switch(event.button) {
            case 0:
                this.optionState.LeftMouse_Down = true;   //判断左键
            break;
            case 2:
                this.optionState.RightMouse_Down = true;  //判断右键
            break;
        }
    }

    /**鼠标右键点击监听回调*/
    private RightClick(e) {
        this.drcs.AddArrTag(this.clickRW.line,this.clickRW.row,0);
        this.ClickDeleBlock(this.drawPos,this.blockSize);
        return false;
    }

    /**右键菜单回调 */
    private RightMenu (e) {
        alert("禁止右键! 防止右键刷新误操作!");
        return false;
    }

    /**鼠标按键松开*/
    private UpCall(e,event) {
        switch(event.button) {
            case 0:   //松开左键
                this.optionState.LeftMouse_Up = true;
                this.optionState.LeftMouse_Down = false;
                this.optionState.LeftMouse_Click = false;
            break;
            case 2:  //松开右键
                this.optionState.RightMouse_Down = false;
                this.optionState.RightMouse_Up = true;
            break;
        }
    }

    /**
    * 图块方向更改 
    */
    private BlockDirection (e,event) {
        switch(event.keyCode) {
            //若按下空格键
            case 32: 
                this.rotateCurrent += this.rotateInterval;
                if(this.rotateCurrent >= 360) {
                    this.rotateCurrent = 0;
                }
                this.setBlockAngle.textContent = " " + this.rotateCurrent + " °";
                DrawClass.ins().RotateImage(this.rotateCurrent);
                break;
        }
    }

    /**提取图片title中的序号 
     * @param img_src 图片源的title内容
    */
    private GetImageIndex (img_src:string) {
        if(img_src != null) {
            //获取"@"标记所在位置
            let inx:number = img_src.indexOf("@");
            let src_arr:string[] = img_src.split("@");
            let img_inx:number = parseInt(src_arr[1]);
            return img_inx;
        }
        return -1;
    }


}

/**操作状态类 */
class StateOption {
    public LeftMouse_Click: boolean = false; //鼠标左键点击
    public LeftMouse_Down: boolean = false; //鼠标左键按下
    public LeftMouse_Up: boolean = false;  //鼠标左键松开
    public RightMouse_Click: boolean =  false; //鼠标右键点击
    public RightMouse_Down: boolean = false; //鼠标右键按下
    public RightMouse_Up: boolean = false; //鼠标右键松开
    public MouseMove_Block: boolean = false;  //鼠标在网格上移动

    private Prototype_Arr:string[] = [];

    public constructor() {

    }

    /**遍历类中的属性
     * @param TorF 返回当前类中为true或false中的属性 
    */
    private ErgodicClass (TorF:boolean) {
        let temp:string  = "";
        let state:StateOption = this;
        this.Prototype_Arr =  this.Prototype_Arr.splice(0,this.Prototype_Arr.length);
        for(let key in state) {
            if(TorF == true && state[key] == true) {
                temp = key;
            }
            if(TorF == false && state[key] == false) {
                temp = key;
            }
            this.Prototype_Arr.push(temp);
        }
    }

    /**置反当前类中为true或false的属性
     * @param type 要置反的true或false类型
    */
    public InversionPrototype(type:boolean) {
        let inx:number = 0;
        let state:StateOption = this;
        let temp:string[] = null;
        this.ErgodicClass(type);
        temp = this.Prototype_Arr;
        for(let proto in state) {
            if(temp[inx] != null) {
                if(proto == temp[inx]) {
                    inx += 1;
                    state[proto] = (!state[proto]);
                }
            }
        }
    }

    /**全属性设置为false或true
     * @param state 设置的状态true或false 默认为false 
    */
    public ResetAll(state:boolean = false) {
        let stateClass:StateOption = this;
        for(let sc in stateClass) {
            stateClass[sc] = state;
        }
    }
}